<?php
/**
 * CK框架 视图类
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
define('CK_APPLICATION_TEMPLATE', CK_APPLICATION_DIR . 'template/');
define('CK_APPLICATION_DATA_TEMPLATE', CK_APPLICATION_DATA_DIR . 'template/');
class view
{
	/**
	 * 模块的目录
	 * 默认为APP_NAME
	 * @var string
	 */
	public static $templateDir = CK_APPLICATION_NAME;

	/**
	 * 视图存储的数据
	 * @var array
	 */
	private static $_data = array();

	/**
	 * 添加/更改数据
	 * @param string $key
	 * @param mixed $value
	 * @return
	 */
	public static function addData ($key, $value)
	{
		self::$_data[$key] = $value;
	}

	/**
	 * 合并数据 会替换现有的数据
	 * @param array $data
	 * @return
	 */
	public static function mergeData ($data)
	{
		if (! is_array($data))
		{
			return;
		}
		if ($data)
		{
			self::$_data = array_merge(self::$_data, $data);
		}
	}
	/**
	 * 输出json数据
	 */
	public static function displayJson()
	{
	    ob_start();
		echo json_encode(self::$_data);
	}
	/**
	 * 输出xml数据
	 */
	public static function displayXml()
	{
	    ob_start();
		echo arrayToXml::addData(self::$_data);
	}
	/**
	 * 输出
	 * @param string $actionName
	 * 控制器名
	 * @param string $methodName
	 * 方法名
	 * @param string $makeFileName
	 * 生成的文件名  该项与$cacheTime只能有一项是成立的 该项如需使用  请填写绝对路径
	 * @param int $cacheTime 
	 * 默认为0 表示不缓存
	 * @todo 如果模板有改动 需要手工删除已经替换好了的模板文件 这里就没有加缓存这些判断了。见谅
	 */
	public static function display ($actionName, $methodName)
	{
		self::$_nowActionName = $actionName;
		//获取模板文件位置
		$templateCompieFile = self::getTemplate($actionName,$methodName);
		extract(self::$_data);
		ob_start();
		include $templateCompieFile;
	}
	/**
	 * 刷新输出
	 * @param string $fileName 生成的静态文件名
	 * @param int $time 生成缓存的事件
	 */
	public static function endFlush($fileName = '',$time = -1)
	{
	    $hasTime = is_int($time) && ($time = (int)$time) > -1 ? true : false;
	    if($fileName || $hasTime)
	    {
	        $content = ob_get_contents();
	        if(!$fileName)
	        {
	            cache::init(cacheType::FILE);
	            cache::set(pageCache::getPageId(), $content,$time);
	        } else 
	        {
	            file::write($fileName, $content);
	        }    
	    } 
	    ob_end_flush();
	}
	private static $_nowActionName = '';
	/**
	 * 获取模板文件路径
	 * @param string $actionName
	 * @param string $methodName
	 * @throws base_Exception
	 * @return string
	 */
	private static function getTemplate($actionName,$methodName)
	{
		$templateFile = CK_APPLICATION_TEMPLATE . self::$templateDir . '/' .$actionName . '/' . $methodName . '.tpl.html';
		$templateCompieFile = CK_APPLICATION_DATA_TEMPLATE . self::$templateDir . '/' .$actionName . '/' . $methodName . '.tpl.php';
		if (!file_exists($templateCompieFile) || config::$configObject->CK_DEVELOP_NOW == 'true')
		{
			//编译文件
			if(!file_exists($templateFile))
			{
				throw new base_Exception(lang::getLang('__NOT_FOUND_VIEW_FILE__',array($templateFile)));
			}
			self::compile($templateFile, $templateCompieFile);
		}
		return $templateCompieFile;
	}
	/**
	 * 插入模板的代码
	 * @param string $actionName
	 * @param string $methodName
	 * @return string
	 */
	private static function insertTmeplate($actionName,$methodName)
	{
		$file = self::getTemplate($actionName,$methodName);
		return "<!--insert[{$actionName}-{$methodName}]start-->\r\n".file_get_contents($file)."\r\n<!--insert[{$actionName}-{$methodName}]end-->\r\n";
	}
	/**
	 * 正则替换模板的回调方法1
	 * @param array $matchs
	 */
	private static function insertTmeplateCallBack1($matchs)
	{
		return self::insertTmeplate($matchs[1],$matchs[2]);
	}
	/**
	 * 正则替换模板的回调方法2
	 * @param array $matchs
	 */
	private static function insertTmeplateCallBack2($matchs)
	{
		return self::insertTmeplate(self::$_nowActionName,$matchs[1]);
	}
	/**
	 * 生成模板页面
	 * @param string $stringFile
	 * @param string $compieFile
	 */
	private static function compile($stringFile,$compieFile)
	{
		$str = file_get_contents($stringFile);
		$str = preg_replace('$([\n\r]+)\t+$s','\\1',$str);
		$str = preg_replace('$\<\?php.+?\?\>$s','',$str);
		$str = preg_replace('$\<\?.+?\?\>$s','',$str);
		$str = preg_replace('$\<\!\-\-\{(.+?)\}\-\-\>$s', '{\\1}',$str);
		
		$str = preg_replace('${template\s+(\S+)\s+\$(\S+)}$',"<?php include self::getTemplate('\\1',$\\2); ?>",$str);
		$str = preg_replace_callback('${template\s+(\S+)\s+(\S+)}$', array(self,'insertTmeplateCallBack1'), $str);
		$str = preg_replace_callback('$\{template\s+(.+)\}$',array(self,'insertTmeplateCallBack2'),$str);
	
		$str = preg_replace('$\{phpcode}(.+?)\{/phpcode\}$s','<?php \\1?>',$str);
		$str = preg_replace('$\{if\s+(.+?)\}$','<?php if(\\1) { ?>',$str);
		$str = preg_replace('$\{else\}$','<?php } else { ?>',$str);
		$str = preg_replace('$\{elseif\s+(.+?)\}$','<?php } elseif (\\1) { ?>',$str);
		$str = preg_replace('$\{\/if\}$','<?php } ?>',$str);
		$str = preg_replace('$\{\/array\}$','<?php } ?>',$str);
		$str = preg_replace('$\{for\s+(.+?)\}$','<?php for(\\1) { ?>',$str);
		$str = preg_replace('$\{\/for\}$','<?php } ?>',$str);
		$str = preg_replace('$\{array\s+(\S+)\s+(\S+)\}$','<?php $tmpArray = \\1;if(is_array($tmpArray)) foreach($tmpArray as \\2) { ?>',$str);
		$str = preg_replace('$\{array\s+(\S+)\s+(\S+)\s+(\S+)\}$','<?php $tmpArray = \\1;if(is_array($tmpArray)) foreach($tmpArray as \\2 => \\3) { ?>',$str);
		$str = preg_replace('$\{(\\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\}$es', "self::addQuote('<?php echo \\1;?>')",$str);
		$str = preg_replace('$\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}$','<?php echo \\1;?>',$str);
		$str = preg_replace('$\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}$','<?php echo \\1;?>',$str);
		$str = preg_replace('$\{(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}$','<?php echo \\1;?>',$str);
		$str = preg_replace('$\{([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)\}$s', '<?php echo \\1;?>',$str);
		$str = preg_replace('$\<\%=(.+?)\.(.+?)\%>$', '<?php echo $\\1->\\2;?>', $str);
		$str = preg_replace('$\<\*=(.+?)\.(.+?)\*>$', '<?php echo ckApplication::loadM(\'\\1\')->\\2;?>', $str);
		$str = preg_replace('$\{form.get\((.+?)\)\}$', '<?php form::formFromArray(\\1);?>', $str);
		$str = preg_replace('$\{form.getFile\((.+?)\)\}$', '<?php form::formFromFile(\\1);?>', $str);
		dir::mkDir(dirname($compieFile));
		file_put_contents($compieFile, $str);
	}
	
	private static function addQuote($var)
	{
		return str_replace("\\\"", "\"", preg_replace('%\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]%s', "['\\1']", $var));
	}
}